package com.csw.shuanfa.utils;


import com.csw.shuanfa.entity.User;

import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * // 设置cron表达式
 * <p>      https://www.pppet.net/
 * //        String cronExpression = "0 30 8 30 * ?";
 * //        CronSequenceGenerator cronSequenceGenerator = new CronSequenceGenerator(cronExpression);
 */
public class TimeUtil {

    static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    public static void main(String[] args) throws Exception {
        //如果当前时间是这个，今天2024-01-31    08:30:00  每天执行时间

        //当前天的执行时间,要求time必须从今天开始,必须大于今天
        String time = "2024-02-01 08:30:00";//周三

        String time_now = "2024-01-21 08:29:00";
        int plus = 3;
        int dayOfMonth = 31;
        int whatMonth = 2;
        int weekDay = 3;
        String hourMinute = "08:30";

        /**
         * 当前端传过来入参的时候需要判断
         */

        LocalDate data_local = LocalDate.parse(time.substring(0, 10));
        LocalDate now_local = LocalDate.parse(time_now.substring(0, 10));
        if (now_local.isAfter(data_local)) {
            throw new RuntimeException("当前时间有误差,开始时间日期必须大于当前时间！");
        }

        String first_time = "";
        /**
         * 天获取时间
         */
        first_time = getFirstTimeDay(time, time_now, plus);


        /**
         * 周获取时间
         */
        first_time = getFirstTimeWeek(time, time_now, plus, weekDay);

        /**
         * 月获取时间
         */
        first_time = getFirstTimeMonth(time, time_now, plus, dayOfMonth, hourMinute);

        /**
         * 年获取时间
         */
        first_time = getFirstTimeYear(time, time_now, whatMonth, plus, dayOfMonth, hourMinute);

        System.out.println(first_time);


    }

    /**
     * 年获取时间
     *
     * @param time       开始日期+时分秒
     * @param time_now   当前时间
     * @param whatMonth  指定那个月
     * @param plusYear   每隔几年
     * @param dayOfMonth 指定每个月几号
     * @return
     * @throws Exception
     */
    public static String getFirstTimeYear(String time, String time_now, int whatMonth, int plusYear, int dayOfMonth, String hourMinute) throws Exception {
        Date now = sdf.parse(time_now);
        String lase_time;
        String first_time;
        String current;
        //三年后1月1号 几点
        LocalDate nextRun4_0 = calculateCurrentRun_year(LocalDate.parse(time.substring(0, 10)), whatMonth, dayOfMonth);
        LocalTime time_4 = LocalTime.parse(hourMinute);
        current = LocalDateTime.of(nextRun4_0, time_4).format(formatter);

        if (now.compareTo(sdf.parse(current)) > 0) {//当前月没希望
            //取下一次的
            first_time = getHowTimeYear(current, plusYear, dayOfMonth, hourMinute);
            lase_time = getHowTimeYear(first_time, plusYear, dayOfMonth, hourMinute);
        } else {
            first_time = current;
            lase_time = getHowTimeYear(first_time, plusYear, dayOfMonth, hourMinute);
        }
        System.out.println("这年（三年后）首次执行时间】" + first_time);
        System.out.println("下次执行时间】" + lase_time);
        return first_time;
    }

    public static String getHowTimeYear(String firstTime, int plusYear, int dayOfMonth, String hourMinute) {
        LocalTime time_4 = LocalTime.parse(hourMinute);
        String lase_time;
        LocalDate nextRun4_2 = calculateNextRun_year(LocalDate.parse(firstTime.substring(0, 10)), plusYear, dayOfMonth);
        lase_time = LocalDateTime.of(nextRun4_2, time_4).format(formatter);
        return lase_time;
    }

    /**
     * 获取首次执行时间
     *
     * @param entity
     * @param nextExecutionTime
     * @param time
     * @param time_now
     * @return
     * @throws Exception //从开始时间里面截取年月日，拼上时分秒作为比较时间，开始时间算作当前时间
     *                   LocalDate nextRun3_0 = LocalDate.parse(entity.getStartTime().substring(0, 10));
     *                   LocalTime time_3 = LocalTime.parse(entity.getHourMinutes());
     *                   String time = LocalDateTime.of(nextRun3_0, time_3).format(formatter);
     *                   entity.setTime(time);
     *                   <p>
     *                   String time_now = entity.getStartTime();
     */
    public static String getNextExecutionTime_first(String cycleType, int plus, int dayOfMonth, String hourMinutes, int weekDay, int whatMonth, String time, String time_now) throws Exception {
        String nextExecutionTime = null;
        if (cycleType.equals(Constant.DAY)) {//日
            nextExecutionTime = TimeUtil.getFirstTimeDay(time, time_now, plus);
        } else if (cycleType.equals(Constant.WEEK)) {//周
            nextExecutionTime = TimeUtil.getFirstTimeWeek(time, time_now, plus, weekDay);
        } else if (cycleType.equals(Constant.MONTH)) {//月
            nextExecutionTime = TimeUtil.getFirstTimeMonth(time, time_now, plus, dayOfMonth, hourMinutes);
        } else if (cycleType.equals(Constant.YEAR)) {//年
            nextExecutionTime = TimeUtil.getFirstTimeYear(time, time_now, whatMonth, plus, dayOfMonth, hourMinutes);
        }
        return nextExecutionTime;
    }

    /**
     * 获取下次执行时间
     *
     * @param entity
     * @return
     * @throws Exception
     */
    public static String getNextExecutionTime_last(String nextExecutionTime, String cycleType, int plus, int dayOfMonth, String hourMinutes) throws Exception {
        boolean xh = false;
        while (xh == false) {
            Date parse = sdf.parse(nextExecutionTime);
            if (parse.compareTo(new Date()) > 0) {//如果大于当前时间说明可以执行到
                xh = true;
                break;
            } else {
                if (cycleType.equals(Constant.DAY)) {//日
                    nextExecutionTime = TimeUtil.getHowTimeDay(nextExecutionTime, plus);
                } else if (cycleType.equals(Constant.WEEK)) {//周
                    nextExecutionTime = TimeUtil.getHowTimeWeek(nextExecutionTime, plus);
                } else if (cycleType.equals(Constant.MONTH)) {//月
                    nextExecutionTime = TimeUtil.getHowTimeMonth(nextExecutionTime, plus, dayOfMonth, hourMinutes);
                } else if (cycleType.equals(Constant.YEAR)) {//年
                    nextExecutionTime = TimeUtil.getHowTimeYear(nextExecutionTime, plus, dayOfMonth, hourMinutes);
                }
            }
        }
        return nextExecutionTime;
    }

    public static Boolean judgeExecutionTime(String endTime, String nextExecutionTime) throws Exception {
        //判断
        Date dateEndTiem = sdf.parse(endTime);
        Date dateNextExecutionTime = sdf.parse(nextExecutionTime);
        if (dateNextExecutionTime.compareTo(dateEndTiem) > 0) {
            return false;
        }
        return true;
    }

    /**
     * 月获取时间
     *
     * @param time       开始日期+时分秒
     * @param time_now   当前时间
     * @param plusMonth  每隔几个月
     * @param dayOfMonth 指定每个月几号
     * @return
     * @throws Exception
     */
    public static String getFirstTimeMonth(String time, String time_now, int plusMonth, int dayOfMonth, String hourMinute) throws Exception {
        Date now = sdf.parse(time_now);
        String lase_time;
        String first_time;
        //找出来当前月，找出当前月的某30号（如果没有这一天就取最后一天），然后和当前时间进行对比，如果当前时间小于它，就去那一天。下次执行时间就取上次执行的年月加几个月加几号（如果没有这一天取最后一天）
        LocalDate nextRun3_0 = calculateCurrentRun_month(LocalDate.parse(time.substring(0, 10)), dayOfMonth);
        LocalTime time_3 = LocalTime.parse(hourMinute);
        String current = LocalDateTime.of(nextRun3_0, time_3).format(formatter);

        if (now.compareTo(sdf.parse(current)) > 0) {//当前月没希望
            //取下一次的
            first_time = getHowTimeMonth(current, plusMonth, dayOfMonth, hourMinute);
            lase_time = getHowTimeMonth(first_time, plusMonth, dayOfMonth, hourMinute);
        } else {
            first_time = current;
            lase_time = getHowTimeMonth(first_time, plusMonth, dayOfMonth, hourMinute);
        }
        System.out.println("这月（三月后）首次执行时间】" + first_time);
        System.out.println("下次执行时间】" + lase_time);
        return first_time;
    }


    /**
     * @param firstTime  可执行时间的年月日
     * @param plusMonth  加几个月
     * @param dayOfMonth 每月几号
     * @param hourMinute 时分秒
     * @return
     */
    public static String getHowTimeMonth(String firstTime, int plusMonth, int dayOfMonth, String hourMinute) {
        LocalTime time_3 = LocalTime.parse(hourMinute);
        String lase_time;
        LocalDate nextRun3_2 = calculateNextRun_month(LocalDate.parse(firstTime.substring(0, 10)), plusMonth, dayOfMonth);
        lase_time = LocalDateTime.of(nextRun3_2, time_3).format(formatter);
        return lase_time;
    }

    /**
     * 周获取时间
     *
     * @param time     开始日期+时分秒
     * @param time_now 当前时间
     * @param plusWeek 每隔几个周
     * @return
     * @throws Exception
     */
    public static String getFirstTimeWeek(String time, String time_now, int plusWeek, int weekDay) throws Exception {
        //计算3周后，周一 几点——比如每三周的周一，08:30:00
        //已经过了这个时间
        Date now = sdf.parse(time_now);
        String judge_time;
        String lase_time;
        String first_time;
        judge_time = getCurrentWeekDay(time, weekDay);
        Date judge_time_date = sdf.parse(judge_time);
        //然后比较当前周的周几和当前时间比大小
        if (now.compareTo(judge_time_date) > 0) {//超过时间，计算三周后
            first_time = getHowTimeWeek(judge_time, plusWeek);
            lase_time = getHowTimeWeek(first_time, plusWeek);
        } else {
            first_time = judge_time;
            lase_time = getHowTimeWeek(first_time, plusWeek);
        }
        System.out.println("三周后首次执行时间】" + first_time);
        System.out.println("下次执行时间】" + lase_time);
        return first_time;
    }

    /**
     * 天获取时间
     *
     * @param time     开始日期+时分秒
     * @param time_now 当前时间
     * @param plusDay  每隔几天
     * @return
     * @throws Exception
     */
    public static String getFirstTimeDay(String time, String time_now, int plusDay) throws Exception {
//        String time = "2024-02-01 08:30:00";//周三
//
//        String time_now = "2024-01-21 08:29:00";
        Date date = sdf.parse(time);
        Date now = sdf.parse(time_now);


        String last_time = "";
        String first_time = "";
        //计算三天后 几点-首次执行时间-比如每天08:30:00
        //如果当前时间大于当前8：30，首次执行时间就是
        //当前时间比预计时间小就是今天没超时
        if (now.compareTo(date) > 0) {//已经过了这个时间
            //计算3天后的今天
            first_time = getHowTimeDay(time, plusDay);
            //计算三天后的三天后
            last_time = getHowTimeDay(first_time, plusDay);
        } else {
            //计算今天的  08:30:00
            first_time = time;
            //三天后的这个时间
            last_time = getHowTimeDay(first_time, plusDay);
        }
        System.out.println("三天后首次执行时间】" + first_time);
        System.out.println("下次执行时间】" + last_time);
        return first_time;
    }


    /**
     * 当前年那一月的那一天
     *
     * @param current
     * @param month
     * @param dayOfMonth
     * @return
     */
    public static LocalDate calculateCurrentRun_year(LocalDate current, int month, int dayOfMonth) {
        //获取当前年某一月的1号
        LocalDate localDate = LocalDate.of(current.getYear(), month, 1);
        //获取当前年，那一月那一日
        LocalDate localDate1 = calculateCurrentRun_month(localDate, dayOfMonth);
        return localDate1;
    }

    /**
     * 那年哪月加几年的那一天
     *
     * @param from
     * @param plusYears
     * @param dayOfMonth
     * @return
     */
    public static LocalDate calculateNextRun_year(LocalDate from, int plusYears, int dayOfMonth) {
        //得到几年后的那一年，那一月
        LocalDate next = from.plusYears(plusYears);
        //确定是那一日
        return calculateCurrentRun_month(next, dayOfMonth);
    }

    /**
     * 那年的那个月，确定那一天
     *
     * @param current
     * @param dayOfMonth
     * @return
     */
    public static LocalDate calculateCurrentRun_month(LocalDate current, int dayOfMonth) {
        LocalDate lastDayOfMonth = current.with(TemporalAdjusters.lastDayOfMonth());
        if (dayOfMonth > lastDayOfMonth.getDayOfMonth()) {
            return lastDayOfMonth;
        } else {
            return LocalDate.of(current.getYear(), current.getMonth(), dayOfMonth);
        }
    }

    /**
     * 当前月加几个月的那一天
     *
     * @param from         只用到了年月
     * @param periodMonths
     * @param dayOfMonth
     * @return
     */
    public static LocalDate calculateNextRun_month(LocalDate from, int periodMonths, int dayOfMonth) {
        //确定那个月
        LocalDate next = from.plusMonths(periodMonths);
        //确定那一日
        return calculateCurrentRun_month(next, dayOfMonth);
    }


    /**
     * 找到当前周的周几
     *
     * @param time
     * @param weekDay
     * @return
     */
    public static String getCurrentWeekDay(String time, int weekDay) {

        LocalDateTime dateTime = LocalDateTime.parse(time, formatter);
        int value = dateTime.getDayOfWeek().getValue();

        // 找到下一个周三
        LocalDateTime nextWednesday = null;
        if (weekDay == 1) {
            nextWednesday = getLocalDateTime(value, weekDay, nextWednesday, dateTime, DayOfWeek.MONDAY);
        } else if (weekDay == 2) {
            nextWednesday = getLocalDateTime(value, weekDay, nextWednesday, dateTime, DayOfWeek.TUESDAY);
        } else if (weekDay == 3) {
            nextWednesday = getLocalDateTime(value, weekDay, nextWednesday, dateTime, DayOfWeek.WEDNESDAY);
        } else if (weekDay == 4) {
            nextWednesday = getLocalDateTime(value, weekDay, nextWednesday, dateTime, DayOfWeek.THURSDAY);
        } else if (weekDay == 5) {
            nextWednesday = getLocalDateTime(value, weekDay, nextWednesday, dateTime, DayOfWeek.FRIDAY);
        } else if (weekDay == 6) {
            nextWednesday = getLocalDateTime(value, weekDay, nextWednesday, dateTime, DayOfWeek.SATURDAY);
        } else if (weekDay == 7) {
            nextWednesday = getLocalDateTime(value, weekDay, nextWednesday, dateTime, DayOfWeek.SUNDAY);
        }

        String resultStr = nextWednesday.format(formatter);
        return resultStr;
    }

    /**
     * 判断往上取星期几还是往下取
     *
     * @param value
     * @param weekDay
     * @param nextWednesday
     * @param dateTime
     * @param monday
     * @return
     */
    public static LocalDateTime getLocalDateTime(int value, int weekDay, LocalDateTime nextWednesday, LocalDateTime dateTime, DayOfWeek monday) {
        if (value <= weekDay) {
            nextWednesday = dateTime.with(TemporalAdjusters.nextOrSame(monday));
        } else {
            nextWednesday = dateTime.with(TemporalAdjusters.previous(monday));
        }
        return nextWednesday;
    }

    /**
     * 当前时间加几周
     *
     * @param time
     * @param plusWeek
     * @return
     */
    public static String getHowTimeWeek(String time, int plusWeek) {
        LocalDateTime dateTime = LocalDateTime.parse(time, formatter);

        // 计算三周后的日期时间
        LocalDateTime threeWeeksLater = dateTime.plusWeeks(plusWeek);

        String res = threeWeeksLater.format(formatter);
        return res;

    }

    /**
     * 天数加几天
     *
     * @param time
     * @param plusDay
     */
    public static String getHowTimeDay(String time, int plusDay) throws Exception {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(time);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, plusDay); // 加三天

        // 获取三天后的时间
        Date threeDaysLater = calendar.getTime();
        String threeDaysLaterStr = sdf.format(threeDaysLater);

        return threeDaysLaterStr;
    }

    /**
     * 将一个时间字符串加几个小时
     *
     * @param timeString
     * @param plus
     * @return
     * @throws Exception
     */
    public static String plusHour(String timeString, int plus) throws Exception {


        Date date = sdf.parse(timeString);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        // 加几个小时
        calendar.add(Calendar.HOUR_OF_DAY, plus);

        Date newDate = calendar.getTime();
        String newTimeString = sdf.format(newDate);
        return newTimeString;

    }

    /**
     * 将一个时间字符串加几天
     *
     * @param timeString
     * @param plus
     * @return
     * @throws Exception
     */
    public static String plusDay(String timeString, int plus) throws Exception {


        Date date = sdf.parse(timeString);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        calendar.add(Calendar.DAY_OF_MONTH, plus);

        Date newDate = calendar.getTime();
        String newTimeString = sdf.format(newDate);
        return newTimeString;
    }


    /**
     * basePersonInspectionList 里面的数据要平均分给ss人
     *
     * @param ss
     * @param basePersonInspectionList
     * @return
     */
    public static List<Long>[] getAssignedTasks(List<User> ss, List<Long> basePersonInspectionList) {
        List<Long>[] assignedTasks = new List[ss.size()];
        for (int i = 0; i < ss.size(); i++) {
            assignedTasks[i] = new ArrayList<>();
        }

        int personIndex = 0;
        for (Long task : basePersonInspectionList) {
            assignedTasks[personIndex].add(task);
            personIndex = (personIndex + 1) % ss.size(); // 轮流分配任务给三个人
        }
        return assignedTasks;
    }
}
